package com.leyou.item.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.vo.PageResult;
import com.leyou.item.dto.*;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @package com.leyou.item.service
 * @description: 商品相关的service层
 * @author: 许超越
 * @date 2019/6/28 11:27
 * @version: V1.0
 */
@Service
public class GoodsService {

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private SpuDetailMapper detailMapper;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private AmqpTemplate amqpTemplate;

    /**
     * 查询商品列表的分页
     *
     * @return
     * @param: page 当前页
     * @param: rows 每页显示的行数
     * @param: saleable 是否已经上架
     * @param: key 搜索商品的关键字
     */
    public PageResult<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, String key) {
        //1.分页
        PageHelper.startPage(page, rows);
        //2.搜索条件的过滤
        Example example = new Example(Spu.class);
        Example.Criteria criteria = example.createCriteria();
        //2.1按照上下架条件查询还是查询全部
        if (saleable != null) {
            criteria.andEqualTo("saleable", saleable);
        }
        //2.2判断是否添加按照key字段模糊查询
        if (StringUtils.isNotBlank(key)) {
            criteria.andLike("name", "%" + key + "%");
        }
        //2.3默认按照更新时间排序n
        example.setOrderByClause("update_time DESC");
        //3.按照条件查询spu
        List<Spu> list = spuMapper.selectByExample(example);
        //判断是否查询到结果
        if (CollectionUtils.isEmpty(list)) {
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //4.封装分页结果
        PageInfo<Spu> spuPageInfo = new PageInfo<>(list);
        //将list内部元素转换成对应DTO类型
        List<SpuDTO> spuDTOList = BeanHelper.copyWithCollection(list, SpuDTO.class);
        // 5.处理分类名称和品牌名称
        handleCategoryAndBrandName(spuDTOList);
        //6.封装号分页数据到实体类中返回
        return new PageResult<>(spuPageInfo.getTotal(), spuDTOList);
    }

    /**
     * 处理分类名称和品牌名称
     *
     * @param： spuDTOList 商品详情集合
     */
    private void handleCategoryAndBrandName(List<SpuDTO> spuDTOList) {
        //遍历结合
        for (SpuDTO spuDTO : spuDTOList) {
            //查询并处理分类信息
            String categoryName = categoryService.queryCategoryByIds(spuDTO.getCategoryIds()).stream().map(CategoryDTO::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(categoryName);
            //查询并处理品牌
            BrandDTO brandDTO = brandService.queryById(spuDTO.getBrandId());
            spuDTO.setBrandName(brandDTO.getName());
        }

    }


    /**
     * 新增商品
     * @param spuDTO 页面提交商品信息
     */
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        //将spuDTO转换成spu
        Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);
        //默认商品添加后下架状态
        spu.setSaleable(false);
        //向tb_spu表中插入数据
        int insertCount = spuMapper.insertSelective(spu);
        //判断插入是否成功
        if (insertCount != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
        //获取spuDetail数据
        SpuDetail spuDetail = BeanHelper.copyProperties(spuDTO.getSpuDetail(), SpuDetail.class);
        //设置添加条件
        spuDetail.setSpuId(spu.getId());
        //插入tb_spu_detail数据
        int insertDetailCount = detailMapper.insertSelective(spuDetail);
        //判断插入是否成功
        if (insertDetailCount != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
        //新增sku表中的数据
        insertSkuList(spuDTO.getSkus(), spuDTO.getId());
    }


    /**
     * 根据spuId更新上下架状态
     * @param: spuId
     */
    @Transactional
    public void updateSpuSaleable(Long spuId, Boolean saleable) {
        //判断前台传递的参数是否可用
        if (saleable == null || spuId == null) {
            throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        //通过spuId修改saleable
        Spu spu = new Spu();
        spu.setId(spuId);
        spu.setSaleable(saleable);
        //更新spu
        int updateSpuCount = spuMapper.updateByPrimaryKeySelective(spu);
        //判断更新是否成功
        if (updateSpuCount != 1) {
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
        //更新sku的enable值
        Sku sku = new Sku();
        sku.setEnable(saleable);
        //设置更新条件条件
        Example example = new Example(Sku.class);
        example.createCriteria().andEqualTo("spuId", spuId);
        //查询需要更新的数据条数
        int count = skuMapper.selectCountByExample(example);
        //更新数据
        int updateSkuCount = skuMapper.updateByExampleSelective(sku, example);
        //判断更新是否成功
        if (count != updateSkuCount) {
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }

        //判断使用的消息队列
        String routeKey = saleable ? MQConstants.RoutingKey.ITEM_UP_KEY : MQConstants.RoutingKey.ITEM_DOWN_KEY;
        //发送目前消息
        amqpTemplate.convertAndSend(MQConstants.Exchange.ITEM_EXCHANGE_NAME, routeKey, spuId);
    }


    /**
     * 通过spuId查询spuDetail数据
     * @param: spuId
     * @return
     */
    public SpuDetailDTO querySpuDetailById(Long spuId) {
        //查询数据
        SpuDetail spuDetail = detailMapper.selectByPrimaryKey(spuId);
        //判断是否查询到数据
        if (spuDetail == null) {
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        //转换数据并返回
        return BeanHelper.copyProperties(spuDetail, SpuDetailDTO.class);
    }


    /**
     * 通过spuId查询sku数据
     * @param: spuId
     * @return
     */
    public List<SkuDTO> querySkuBySpuId(Long spuId) {
        //设置查询数据
        Sku sku = new Sku();
        sku.setSpuId(spuId);
        //设置查询条件
        Example example = new Example(Sku.class);
        example.createCriteria().andEqualTo("spuId", spuId);
        //查询
        List<Sku> skus = skuMapper.selectByExample(example);
        //判断是否查询到数据
        if (CollectionUtils.isEmpty(skus)) {
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(skus, SkuDTO.class);
    }


    /**
     * 更新商品
     * @param: spuDTO 更新商品的数据
     */
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        //获取spuId
        Long spuId = spuDTO.getId();
        if (spuId == null) {
            throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        //1.删除原先的sku里面的数据
        //1.1设置查询的条件的数据
        Sku sku = new Sku();
        sku.setSpuId(spuId);
        //1.2查询删除前数据条数
        int oldSkuCount = skuMapper.selectCount(sku);
        //1.3删除所有数据
        int deleteCount = skuMapper.delete(sku);
        //1.4判断删除是否成功
        if (deleteCount != oldSkuCount) {
            throw new LyException(ExceptionEnum.DELETE_OPERATION_FAIL);
        }
        //2.更新spu表中的数据
        Spu spu = BeanHelper.copyProperties(spuDTO, Spu.class);
        //2.1保证商品更新的安全
        spu.setSaleable(null);
        spu.setUpdateTime(null);
        spu.setCreateTime(null);
        //2.2更新数据
        int updateSpuCount = spuMapper.updateByPrimaryKeySelective(spu);
        //2.3判断更新是否成功
        if (updateSpuCount != 1) {
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
        //3.更新spuDetail中的数据
        //3.1获取tb_spu_detail表中的数据
        SpuDetail spuDetail = BeanHelper.copyProperties(spuDTO.getSpuDetail(), SpuDetail.class);
        //3.2清空表中的创建和更新时间
        spuDetail.setCreateTime(null);
        spuDetail.setUpdateTime(null);
        //3.3执行更新
        int updateSpuDetailCount = detailMapper.updateByPrimaryKeySelective(spuDetail);
        //3.4判断更新操作是否成功
        if (updateSpuDetailCount != 1) {
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
        //4.从新插入sku表中的数据
        insertSkuList(spuDTO.getSkus(), spuId);

    }

    /**
     * 工具类：
     * 新增tb_sku表中的数据
     * @param: skuDTOList
     * @param: spuId
     */
    private void insertSkuList(List<SkuDTO> skuDTOList, Long spuId) {
        //获取skus集合数据
        List<Sku> skus = BeanHelper.copyWithCollection(skuDTOList, Sku.class);
        //遍历数据，设置商品的spu_id和enable下架状态
        for (Sku sku : skus) {
            sku.setSpuId(spuId);
            sku.setEnable(false);
        }
        //批量插入数据
        int insertListCount = skuMapper.insertList(skus);
        //判断插入是否成功
        if (insertListCount != skus.size()) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    /**
     * 根据spuId查询spu
     * @param: spuId
     * @return
     */
    public SpuDTO querySpuById(Long spuId) {
        //查询spu
        Spu spu = spuMapper.selectByPrimaryKey(spuId);
        //转换成spuDTO
        SpuDTO spuDTO = BeanHelper.copyProperties(spu, SpuDTO.class);
        //查询spu_detail,将属性封装进spuDTO中
        spuDTO.setSpuDetail(querySpuDetailById(spuId));
        //查询skus并封装进spuDTO中
        spuDTO.setSkus(querySkuBySpuId(spuId));
        //返回结果
        return spuDTO;
    }


    /**
     * 根据skuId集合查询sku
     * @param ids
     * @return
     */
    public List<SkuDTO> querySkuByIds(List<Long> ids) {
        //查询sku
        List<Sku> skuList = skuMapper.selectByIdList(ids);
        //判断是否查询到了
        if (CollectionUtils.isEmpty(skuList)) {
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(skuList, SkuDTO.class);
    }


    /**
     * 减库存
     * @param cartMap 商品id及数量的map
     */
    @Transactional
    public void minusStock(Map<Long, Integer> cartMap) {
        for (Map.Entry<Long, Integer> entry : cartMap.entrySet()) {
            Long skuId = entry.getKey();
            Integer num = entry.getValue();
            int count = skuMapper.minusStock(skuId, num);
            if(count != 1){
                throw new RuntimeException("库存不足");
            }
        }
    }


    /**
     * 增加库存
     * @param skuMap 商品id和商品数量
     * @return
     */
    @Transactional
    public void plusStock(Map<Long, Integer> skuMap) {
        for (Map.Entry<Long, Integer> entry : skuMap.entrySet()) {
            Long skuId = entry.getKey();
            Integer num = entry.getValue();
            int count = skuMapper.plusStock(skuId, num);
            if (count != 1) {
                throw new RuntimeException("恢复库存失败！");
            }
        }
    }
}
